const fs = require('fs');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const path = require('path');
const babel = require('@babel/core');

const getModuleInfo = (file) => {
    const body = fs.readFileSync(file, 'utf-8');
    const ast = parser.parse(body, {
        sourceType: 'module'//告诉 babel 我们的代码是 ES 模块
    })
    const deps = {
    };
    traverse(ast, {
        ImportDeclaration({ node }) {
            const dirname = path.dirname(file);
            const abspath = './' + path.join(dirname, node.source.value);
            // console.log(abspath);
            deps[node.source.value] = abspath;

        }
    })
    // console.log(ast);

    //根据 ast 生成新的代码
    const { code } = babel.transformFromAst(ast, null, {
        presets: ['@babel/preset-env']
    })
    const moduleInfo = {
        file: file,
        deps: deps,
        code: code,
    }
    return moduleInfo;

}

const parseModules = (file) => {
    const entry = getModuleInfo(file);
    const temp = [entry]
    for (let i = 0; i < temp.length; i++) {
        const deps = temp[i].deps;
        if (deps) {
            for (let key in deps) {
                if (deps.hasOwnProperty(key)) {
                    temp.push(getModuleInfo(deps[key]));
                }
            }
        }
    }
    // console.log(temp);

    const depsGraph = {}
    temp.forEach(moduleInfo => {
        depsGraph[moduleInfo.file] = {
            deps: moduleInfo.deps,
            code: moduleInfo.code,
        }
    })
    return depsGraph
}

//处理一下 require 和 exports 这两个关键字
const bundle = (file) => {
    const depsGraph = JSON.stringify(parseModules(file));
    return `(function(graph) {
            function require(file) {

              function absRequire(relPath) {
                return require(graph[file].deps[relPath])
              }

              var exports = {};

              (function(require, exports, code) {
                eval(code)
              })(absRequire, exports, graph[file].code);
              
              return exports
            }
            require("${file}")
          })(${depsGraph});`
}

const content = bundle('./src/index.js');
console.log(content);
fs.mkdirSync('./dist');
fs.writeFileSync('./dist/bundle.js', content);


